package com.sluggard.workflow;

import com.sluggard.workflow.properties.WorkflowConfigConstants;
import com.sluggard.workflow.properties.WorkflowConfigProperties;
import io.micrometer.common.util.StringUtils;
import jakarta.annotation.Resource;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.camunda.bpm.engine.IdentityService;
import org.camunda.bpm.engine.ProcessEngine;
import org.camunda.bpm.engine.impl.history.HistoryLevel;
import org.camunda.bpm.engine.spring.SpringProcessEngineConfiguration;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.PlatformTransactionManager;

import javax.sql.DataSource;
import java.util.HashMap;
import java.util.Map;

/**
 * @author lizheng
 * @since 2024.4.18
 */
@Slf4j
@Configuration
@ComponentScan(basePackages = "com.sluggard.workflow")
@EnableConfigurationProperties({WorkflowConfigProperties.class})
@ConditionalOnProperty(name = WorkflowConfigConstants.ENABLE_WORKFLOW, havingValue = "true", matchIfMissing = true)
@ConditionalOnClass({DataSource.class})
public class DefaultCamundaAutoConfiguration {

    private Map<String, HistoryLevel> historyLevelMap = new HashMap<>();

    public DefaultCamundaAutoConfiguration() {
        log.info(WorkflowConfigConstants.LOADING_WORKFLOW_AUTO_CONFIGURE);
        historyLevelMap.put(HistoryLevel.HISTORY_LEVEL_FULL.getName(), HistoryLevel.HISTORY_LEVEL_FULL);
        historyLevelMap.put(HistoryLevel.HISTORY_LEVEL_AUDIT.getName(), HistoryLevel.HISTORY_LEVEL_AUDIT);
        historyLevelMap.put(HistoryLevel.HISTORY_LEVEL_NONE.getName(), HistoryLevel.HISTORY_LEVEL_NONE);
        historyLevelMap.put(HistoryLevel.HISTORY_LEVEL_ACTIVITY.getName(), HistoryLevel.HISTORY_LEVEL_ACTIVITY);
    }

    @Resource
    ApplicationContext applicationContext;

    @Bean(name = "camundaBpmTransactionManager")
    public PlatformTransactionManager defaultTransactionManager(DataSource dataSource) {
        return new DataSourceTransactionManager(dataSource);
    }

    /**
     * 流程配置，与spring整合采用SpringProcessEngineConfiguration这个实现
     *
     * @param dataSource
     * @param transactionManager
     * @return
     */
    @Bean
    @SneakyThrows
    public SpringProcessEngineConfiguration processEngineConfiguration(DataSource dataSource,
                                                                     @Qualifier("camundaBpmTransactionManager") PlatformTransactionManager transactionManager,
                                                                     WorkflowConfigProperties workflowConfigProperties) {
        SpringProcessEngineConfiguration processEngineConfiguration = new SpringProcessEngineConfiguration();
        processEngineConfiguration.setDataSource(dataSource);
        processEngineConfiguration.setDatabaseSchemaUpdate(workflowConfigProperties.getSchemeUpdate());
        processEngineConfiguration.setDatabaseType(workflowConfigProperties.getDatabaseType());
        processEngineConfiguration.setHistoryLevel(historyLevelMap.getOrDefault(workflowConfigProperties.getHistoryLevel(), HistoryLevel.HISTORY_LEVEL_FULL));
        processEngineConfiguration.setHistoryTimeToLive(workflowConfigProperties.getHistoryTimeToLive());
        processEngineConfiguration.setTransactionManager(transactionManager);

        if(StringUtils.isNotBlank(workflowConfigProperties.getProcessEngineName())){
            processEngineConfiguration.setProcessEngineName(workflowConfigProperties.getProcessEngineName());
        }

        if(workflowConfigProperties.isCustomIdentityService()){
            processEngineConfiguration.setIdentityService(applicationContext.getBean(workflowConfigProperties.getCustomIdentityServiceName(), IdentityService.class));
        }
        return processEngineConfiguration;
    }

    @Bean
    public ProcessEngine processEngine(SpringProcessEngineConfiguration processEngineConfiguration){
        return processEngineConfiguration.buildProcessEngine();
    }

}
